#include "HttpParse.h"

static int IsHttp(const struct TcpHeader *tcpHeader)
{
	assert(tcpHeader != NULL);

	unsigned short srcPort = ntohs(tcpHeader->srcPort);
	unsigned short dstPort = ntohs(tcpHeader->dstPort);

	if (srcPort == 80 || dstPort == 80 ||
			srcPort == 8080 || dstPort == 8080) {
		return 1;   
	}   
					    
	return 0;
}


extern void PacketProcessing(const unsigned char *packet, unsigned int length)
{
	assert(packet != NULL);
 	rawPacketCount++;
#if 0
	/* not ip  */
	if (packet[12] != 0x08 && packet[13] != 0x00)
		return;
#endif
	/* not tcp */
	if (packet[9] != 0x06)
		return;

	/* not my idea */
	if (length <= 60) 
		return;

	struct IpHeader *ipHeader = packet;
//	struct IpHeader *ipHeader = (struct IpHeader *)(packet + sizeof(struct EthHeader));
	struct TcpHeader *tcpHeader = (struct TcpHeader *)((unsigned char *)ipHeader + ipHeader->ihl*4);        

	if ( IsHttp(tcpHeader) ) { 
		HttpParse(ipHeader, length - sizeof(struct EthHeader));
	}   

	return;
}


static void HttpParse(const struct IpHeader *ipHeader, unsigned int ipLength)
{
	assert(ipHeader != NULL);
	struct TcpHeader *tcpHeader = (struct TcpHeader *)((unsigned char *)ipHeader + ipHeader->ihl*4);        
	int headLength = ipHeader->ihl * 4 + tcpHeader->thl * 4;
	int isReq;
	unsigned short srcPort = ntohs(tcpHeader->srcPort);
	unsigned short dstPort = ntohs(tcpHeader->dstPort);
	httpPacketCount++;

	if (dstPort == 80 || dstPort == 8080) {
		isReq = 1;
		if (tcpHeader->psh == 1 && tcpHeader->ack == 1 &&
				tcpHeader->fin == 0 && tcpHeader->syn == 0 &&
				tcpHeader->rst == 0 && tcpHeader->urg == 0) {

			BuildPacket(isReq, tcpHeader->ackNum, tcpHeader->seqNum, ipHeader, headLength, ipLength);
		} // later connect packet
	} else if (srcPort == 80 || srcPort == 8080) {
		isReq = 0;
		BuildPacket(isReq, tcpHeader->ackNum, tcpHeader->seqNum, ipHeader, headLength, ipLength);
	}

}


static void BuildPacket(int isReq, unsigned int ack, unsigned int seq, const struct IpHeader *ipHeader, int start, int ipLength)
{
	assert(ipHeader != NULL);
	int i;
	char *data = (char *)ipHeader + start;

	if (isReq) {
		if ( AddMethodAndURL(data, httpSession[sessionID].method, httpSession[sessionID].url) == 0 ) 
			printf("warning: no method or url\n");
		httpSession[sessionID].sendTime = time(NULL);
		httpSession[sessionID].id = sessionID;
		httpSession[sessionID].ack = ack;
		sessionID++;

		IsSessionIDMax();
	} else {
		for (i = 0; i < sessionID; i++) {
			if (seq == httpSession[i].ack) 
				break;	
		}
		if (i == sessionID)
			return;

		if ( AddStatucode(data, httpSession[i].statucode)  == 0 )
			return;	

		if ( AddContentTypeAndLength(data, httpSession[i].contentType, httpSession[i].contentLength) == 0 ) 
			return;
	
		httpSession[i].responseTime = time(NULL);
		PrintResult(i);		
	}
}


static int AddMethodAndURL(const char *data, char *method, char *url)
{
	assert(data != NULL && url != NULL);
	char *frontHost, *endHost, *frontURL, *endURL;
	int lengthHost, lengthURL, lengthHead;

	lengthHead = sizeof("http://") - 1;
	memcpy(url, "http://", lengthHead);

    frontHost = strstr(data, "Host:");
	if (frontHost) {
		frontHost += sizeof("Host:");
	} else {
		return 0;
	}       
	endHost = strstr(frontHost, "\r\n");
	if (endHost) {
		lengthHost = endHost - frontHost; 
	} else {
		return 0;
	}
	memcpy(url + lengthHead, frontHost, lengthHost);

	frontURL = strstr(data, "GET");
	if (frontURL) {
		memcpy(method, "GET", 3);
		*(method + 3) = '\0';
		frontURL += sizeof("GET");
	} else {
		frontURL = strstr(data, "POST");
		if (frontURL) {
			memcpy(method, "POST", 4);
			*(method + 4) = '\0';
			frontURL += sizeof("POST");
		} else {
			return 0;
        }
	}

	endURL = strstr(frontURL, " ");
	if (endURL) {
		lengthURL = endURL - frontURL;
	} else {
		return 0;
	}
	memcpy(url + lengthHead + lengthHost, frontURL, lengthURL);
	*(url + lengthHead + lengthHost + lengthURL) = '\0';

	return 1;
}


static int AddStatucode(const char *data, char *statucode)
{
	char *frontCode, *endCode;	
	int lengthCode;
	
	frontCode = strstr(data, "HTTP/1.");
	if (frontCode) {
		frontCode += 9;
	} else {
		return 0;
	}
	 
	endCode = strstr(frontCode, " ");
	if (endCode) {
		lengthCode = endCode - frontCode;
	} else {
		return 0;
	}

	memcpy(statucode, frontCode, lengthCode);
	*(statucode + lengthCode) = '\0';

	return 1;
}
	

static int AddContentTypeAndLength(const char *data, char *type, char *length)
{
	char *frontType, *endType, *frontLength, *endLength;
	int lengthType, lengthLength;

	frontType = strstr(data, "Content-Type:");
	if (frontType) {
		frontType += sizeof("Content-Type:");
	} else {
		return 0;
	}

	endType = strstr(frontType, "\r\n");
	if (endType) {
		lengthType = endType - frontType;
	} else {
		return 0;
	}

	memcpy(type, frontType, lengthType);
	*(type + lengthType) = '\0';

	frontLength = strstr(data, "Content-Length:");
	if (frontLength) {
		frontLength += sizeof("Content-Length:");
	} else {
		return 0;
	}

	endLength = strstr(frontLength, "\r\n");
	if (endLength) {
		lengthLength = endLength - frontLength;
	} else {
		return 0;
	}

	memcpy(length, frontLength, lengthLength);
	*(length + lengthLength) = '\0';

	return 1;
}


static void PrintResult(int id)
{
	printf("Method: %s\n", httpSession[id].method);
	printf("Result: %s\n", httpSession[id].statucode);
	printf("Time: %lf\n", difftime(httpSession[id].responseTime, httpSession[id].sendTime));
	printf("Content-Type: %s\n", httpSession[id].contentType);
	printf("Content-Length: %s\n", httpSession[id].contentLength);
	printf("URL: %s\n\n", httpSession[id].url);
}

static void	IsSessionIDMax()
{
	if (sessionID == 100000)
		sessionID = 0;
}
